# -*- coding: utf-8 -*-
"""时间工具模块
提供时间日期处理和格式化功能
"""

import time
from datetime import datetime, timezone

import pytz


class TimeUtils:
    """时间工具类"""

    # 标准时间格式定义
    FORMAT_DATE = "%Y-%m-%d"
    FORMAT_TIME = "%H:%M:%S"
    FORMAT_DATETIME = "%Y-%m-%d %H:%M:%S"
    FORMAT_DATETIME_MS = "%Y-%m-%d %H:%M:%S.%f"
    FORMAT_ISO = "%Y-%m-%dT%H:%M:%S"
    FORMAT_ISO_MS = "%Y-%m-%dT%H:%M:%S.%f"

    @staticmethod
    def format_datetime(dt=None, format_str=None):
        """格式化日期时间

        Args:
            dt: datetime对象，如果为None则使用当前时间
            format_str: 格式化字符串，如果为None则使用默认格式

        Returns:
            str: 格式化后的日期时间字符串
        """
        if dt is None:
            dt = datetime.now()

        if format_str is None:
            format_str = TimeUtils.FORMAT_DATETIME

        return dt.strftime(format_str)

    @staticmethod
    def parse_datetime(dt_str, format_str=None):
        """解析日期时间字符串

        Args:
            dt_str: 日期时间字符串
            format_str: 格式化字符串，如果为None则尝试多种格式

        Returns:
            datetime: 解析后的datetime对象
        """
        if not dt_str:
            return None

        # 如果指定了格式，直接使用
        if format_str:
            try:
                return datetime.strptime(dt_str, format_str)
            except ValueError:
                raise ValueError(
                    f"无法解析日期时间 '{dt_str}' 为格式 '{format_str}'"
                )

        # 尝试多种常见格式
        formats = [
            TimeUtils.FORMAT_DATETIME_MS,
            TimeUtils.FORMAT_DATETIME,
            TimeUtils.FORMAT_DATE,
            TimeUtils.FORMAT_ISO_MS,
            TimeUtils.FORMAT_ISO,
            "%Y/%m/%d",
            "%Y/%m/%d %H:%M:%S",
            "%d-%m-%Y",
            "%d-%m-%Y %H:%M:%S",
            "%m/%d/%Y",
            "%m/%d/%Y %H:%M:%S",
        ]

        for fmt in formats:
            try:
                return datetime.strptime(dt_str, fmt)
            except ValueError:
                continue

        # 如果都失败，尝试使用更灵活的解析方法
        try:
            return datetime.fromisoformat(dt_str.replace("Z", "+00:00"))
        except ValueError:
            raise ValueError(f"无法解析日期时间 '{dt_str}'")

    @staticmethod
    def convert_timezone(dt, from_tz=None, to_tz=None):
        """转换时区

        Args:
            dt: datetime对象或时间戳
            from_tz: 源时区，可以是字符串或pytz时区对象，如果为None则假定为本地时区
            to_tz: 目标时区，可以是字符串或pytz时区对象，如果为None则使用UTC

        Returns:
            datetime: 转换后的datetime对象
        """
        # 处理时间戳
        if isinstance(dt, (int, float)):
            dt = datetime.fromtimestamp(dt)

        # 确保dt是datetime对象
        if not isinstance(dt, datetime):
            raise TypeError("dt参数必须是datetime对象或时间戳")

        # 处理源时区
        if from_tz is None:
            # 如果dt没有时区信息，假定为本地时区
            if dt.tzinfo is None:
                from_tz = TimeUtils.get_local_timezone()
            else:
                # dt已经有时区信息，使用它
                from_tz = dt.tzinfo
        elif isinstance(from_tz, str):
            from_tz = pytz.timezone(from_tz)

        # 处理目标时区
        if to_tz is None:
            to_tz = pytz.UTC
        elif isinstance(to_tz, str):
            to_tz = pytz.timezone(to_tz)

        # 确保dt有时区信息
        if dt.tzinfo is None:
            dt = from_tz.localize(dt)
        else:
            # 转换到源时区
            dt = dt.astimezone(from_tz)

        # 转换到目标时区
        return dt.astimezone(to_tz)

    @staticmethod
    def get_local_timezone():
        """获取系统本地时区

        Returns:
            pytz.timezone: 本地时区对象
        """
        # 获取系统时区名称
        local_tz_name = time.tzname[0]

        try:
            # 尝试直接使用系统时区名称
            return pytz.timezone(local_tz_name)
        except pytz.exceptions.UnknownTimeZoneError:
            # 如果失败，使用UTC偏移量
            offset = datetime.now().astimezone().utcoffset()
            offset_hours = offset.total_seconds() / 3600
            tz_sign = "-" if offset_hours > 0 else "+"
            tz_hours = abs(int(offset_hours))
            tz_name = f"Etc/GMT{tz_sign}{tz_hours}"
            return pytz.timezone(tz_name)

    @staticmethod
    def get_utc_datetime():
        """获取当前UTC时间

        Returns:
            datetime: 当前UTC时间，包含时区信息
        """
        return datetime.now(timezone.utc)

    @staticmethod
    def to_utc(dt):
        """转换为UTC时间

        Args:
            dt: datetime对象

        Returns:
            datetime: UTC时间，包含时区信息
        """
        return TimeUtils.convert_timezone(dt, to_tz=pytz.UTC)

    @staticmethod
    def from_utc(dt):
        """从UTC时间转换为本地时间

        Args:
            dt: UTC时间

        Returns:
            datetime: 本地时间
        """
        return TimeUtils.convert_timezone(dt, from_tz=pytz.UTC)

    @staticmethod
    def calculate_time_difference(dt1, dt2, unit="seconds"):
        """计算两个日期时间之间的差值

        Args:
            dt1: 第一个日期时间
            dt2: 第二个日期时间
            unit: 单位，可以是'seconds', 'minutes', 'hours', 'days'

        Returns:
            float: 时间差值
        """
        # 确保两个参数都是datetime对象
        if isinstance(dt1, str):
            dt1 = TimeUtils.parse_datetime(dt1)
        if isinstance(dt2, str):
            dt2 = TimeUtils.parse_datetime(dt2)

        # 计算差值
        diff = abs(dt2 - dt1)

        # 转换为指定单位
        if unit == "seconds":
            return diff.total_seconds()
        elif unit == "minutes":
            return diff.total_seconds() / 60
        elif unit == "hours":
            return diff.total_seconds() / 3600
        elif unit == "days":
            return diff.days + diff.seconds / 86400
        else:
            raise ValueError(f"不支持的时间单位: {unit}")

    @staticmethod
    def format_relative_time(dt, now=None):
        """格式化相对时间（如'N天前'）

        Args:
            dt: 日期时间
            now: 当前时间，如果为None则使用当前时间

        Returns:
            str: 格式化后的相对时间字符串
        """
        if now is None:
            now = datetime.now()

        # 确保dt是datetime对象
        if isinstance(dt, str):
            dt = TimeUtils.parse_datetime(dt)

        # 计算差值
        diff = now - dt
        seconds = diff.total_seconds()

        # 根据差值返回不同的描述
        if seconds < 60:
            return f"{int(seconds)}秒前"
        elif seconds < 3600:
            minutes = int(seconds / 60)
            return f"{minutes}分钟前"
        elif seconds < 86400:
            hours = int(seconds / 3600)
            return f"{hours}小时前"
        elif seconds < 2592000:  # 30天
            days = diff.days
            return f"{days}天前"
        elif seconds < 31536000:  # 365天
            months = int(seconds / 2592000)
            return f"{months}个月前"
        else:
            years = int(seconds / 31536000)
            return f"{years}年前"

    @staticmethod
    def get_timestamp(dt=None, ms=False):
        """获取时间戳

        Args:
            dt: datetime对象，如果为None则使用当前时间
            ms: 是否返回毫秒级时间戳

        Returns:
            int: 时间戳
        """
        if dt is None:
            dt = datetime.now()
        elif isinstance(dt, str):
            dt = TimeUtils.parse_datetime(dt)

        if ms:
            return int(dt.timestamp() * 1000)
        else:
            return int(dt.timestamp())

    @staticmethod
    def from_timestamp(ts):
        """从时间戳创建datetime对象

        Args:
            ts: 时间戳，可以是秒级或毫秒级

        Returns:
            datetime: datetime对象
        """
        # 判断是否为毫秒级时间戳
        if isinstance(ts, (int, float)) and ts > 10**12:
            ts = ts / 1000

        return datetime.fromtimestamp(ts)


class Timer:
    """计时器工具类"""

    def __init__(self):
        """初始化计时器"""
        self.start_time = 0
        self.end_time = 0
        self.elapsed_time = 0
        self.is_running = False
        self.threshold = None

    def start(self):
        """开始计时"""
        self.start_time = time.time()
        self.is_running = True

    def stop(self):
        """停止计时"""
        if self.is_running:
            self.end_time = time.time()
            self.elapsed_time = self.end_time - self.start_time
            self.is_running = False

    def reset(self):
        """重置计时器"""
        self.start_time = 0
        self.end_time = 0
        self.elapsed_time = 0
        self.is_running = False

    def get_elapsed_time(self, unit="seconds"):
        """获取经过的时间

        Args:
            unit: 单位，可以是'seconds', 'milliseconds', 'minutes', 'hours'

        Returns:
            float: 经过的时间
        """
        if self.is_running:
            # 如果计时器正在运行，计算从开始到现在的时间
            current_time = time.time()
            elapsed = current_time - self.start_time
        else:
            elapsed = self.elapsed_time

        # 转换为指定单位
        if unit == "seconds":
            return elapsed
        elif unit == "milliseconds":
            return elapsed * 1000
        elif unit == "minutes":
            return elapsed / 60
        elif unit == "hours":
            return elapsed / 3600
        else:
            raise ValueError(f"不支持的时间单位: {unit}")

    def set_threshold(self, threshold_seconds):
        """设置时间阈值

        Args:
            threshold_seconds: 时间阈值（秒）
        """
        self.threshold = threshold_seconds

    def check_threshold(self):
        """检查是否超过时间阈值

        Returns:
            tuple: (是否超过阈值, 当前经过的时间)
        """
        if self.threshold is None:
            return False, 0

        elapsed = self.get_elapsed_time()
        return elapsed > self.threshold, elapsed

    def format_elapsed_time(self):
        """格式化经过的时间为可读字符串

        Returns:
            str: 格式化后的时间字符串
        """
        elapsed = self.get_elapsed_time()

        if elapsed < 0.001:
            return f"{elapsed * 1000000:.2f} μs"
        elif elapsed < 1:
            return f"{elapsed * 1000:.2f} ms"
        elif elapsed < 60:
            return f"{elapsed:.2f} s"
        elif elapsed < 3600:
            minutes, seconds = divmod(elapsed, 60)
            return f"{int(minutes)} m {seconds:.2f} s"
        else:
            hours, remainder = divmod(elapsed, 3600)
            minutes, seconds = divmod(remainder, 60)
            return f"{int(hours)} h {int(minutes)} m {seconds:.2f} s"

    def __enter__(self):
        """上下文管理器入口，用于with语句"""
        self.start()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """上下文管理器出口"""
        self.stop()
        # 检查是否超过阈值并告警
        if self.threshold is not None:
            is_over, elapsed = self.check_threshold()
            if is_over:
                print(
                    f"警告: 操作时间超过阈值 {self.threshold} 秒，实际用时 {elapsed:.2f} 秒"
                )

        # 不抑制异常
        return False
